import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges, ElementRef, ViewChild, OnDestroy } from '@angular/core';
import { CanvasMode, StrokeCollection, Stroke } from '../../models/canvas';

@Component({
  selector: 'app-imageview',
  templateUrl: './imageview.component.html',
  styleUrls: ['./imageview.component.scss']
})
export class ImageviewComponent implements OnInit, OnChanges, OnDestroy {

  @Input() imageUri: string;
  @Input() scaleSeed = 0.1;
  @Input() minScale = 0.1;
  @Input() brightnessSeed = 0.1;
  @Input() minBrightness = 0.1;
  @Input() canRotate = true;
  @Input() canScale = true;
  @Input() canMove = true;
  @Input() canSetBrightness = true;
  @Output() whenCloseViewer = new EventEmitter();
  @ViewChild('img') img: ElementRef;
  @ViewChild('canvas') canvas: ElementRef;
  isLoading = true;
  rotateStyle = {};
  imageStyle = {};
  private mode: CanvasMode = CanvasMode.Drawing;
  private strokes = new StrokeCollection();
  private currentStroke: Stroke;
  private lastPoint = {'x': 0, 'y': 0};
  private isMouseDown = false;
  private isTouchEvent = false;
  private existImageMove = false;
  private moveStartAction = (event) => this.onInputDeviceEvent(event, 'start');
  private movingAction = (event) => this.onInputDeviceEvent(event, 'move');
  private moveEndAction = (event) => this.onInputDeviceEvent(event, 'end');
  constructor() { }

  ngOnInit() {
  }
  ngOnDestroy() {
    this.deattachMoveEvent();
  }
  ngOnChanges(simpleChange: SimpleChanges) {
  }
  /**
   * 关闭处理
   */
  onCloseViwer() {
    if (this.whenCloseViewer) {
      this.whenCloseViewer.emit(this);
    }
  }
  /**
   * 图片加载完成处理
   */
  onImageLoaded() {
    const imageWidth = this.imgElement.naturalWidth;
　  const imageHeight = this.imgElement.naturalHeight;
    const parentWidth = this.imgElement.parentElement.offsetWidth;
    const parentHeight = this.imgElement.parentElement.offsetHeight;
    const level = imageWidth / imageHeight;
    let newWidth = 0, newHeight = parentHeight;
    newWidth = newHeight * level;
    if (newWidth > parentWidth) {
      newWidth = parentWidth;
      newHeight = newWidth / level;
    }
    const left = (parentWidth - newWidth) / 2;
    const top = (parentHeight - newHeight) / 2;
    this.currentImagePos = {'left': left, 'top': top};
    this.canvasElement.width = parentWidth;
    this.canvasElement.height = parentHeight;

    // 订阅图片移动事件
    if (this.canMove) {
      this.attachMoveEvent();
    }
    this.isLoading = false;
  }

  //#region 属性 get、set
  /**
   * 获取当前图片位置
   */
  get currentImagePos(): {'left': number, 'top': number} {
    return {'left': this.imgElement.offsetLeft, 'top': this.imgElement.offsetTop};
  }
  /**
   * 设置当前图片位置
   */
  set currentImagePos(pos: {'left': number, 'top': number}) {
    const oldValue = this.currentImagePos;
    if (oldValue.left !== pos.left || oldValue.top !== pos.top) {
      this.imgElement.style.left = `${pos.left}px`;
      this.imgElement.style.top = `${pos.top}px`;
      this.onPositionChanged(oldValue, pos);
    }
  }
  /**
   * 当前旋转角度值
   */
  get currentDegree(): number {
    const degreeAttr = this.getImageAtribute('degree');
    return degreeAttr ? +degreeAttr : 0;
  }
  /**
   * 设置当前旋转角度值
   */
  set currentDegree(degree: number) {
    const oldValue = this.currentDegree;
    if (oldValue !== degree) {
      this.setImageAtribute('degree', degree);
      this.onRotateDegreeChanged(oldValue, degree);
    }
  }
   /**
   * 获取当前img元素缩放比例值
   */
  get currentScale(): number {
    const zoomLevelAttr = this.getImageAtribute('zoomLevel');
    return zoomLevelAttr ? +zoomLevelAttr : 1;
  }
  /**
   * 设置当前img元素缩放比例值
   */
  set currentScale(scale: number) {
    const oldValue = this.currentScale;
    if (oldValue !== scale) {
      this.setImageAtribute('zoomLevel', scale);
      this.onScaleChanged(oldValue, scale);
    }
  }
  /**
   * 获取图片当前亮度值
   */
  get currentBrightness(): number {
    const brightnessAttr = this.getImageAtribute('brightness');
    return brightnessAttr ? +brightnessAttr : 1;
  }
  /**
   * 设置图片当前亮度值
   */
  set currentBrightness(brightness: number) {
    const oldValue = this.currentBrightness;
    if (oldValue !== brightness) {
      this.setImageAtribute('brightness', brightness);
      this.onBrightnessChanged(oldValue, brightness);
    }
  }
  //#endregion

  //#region 鼠标、触控事件处理
  onInputDeviceEvent(event, type: 'start' | 'move' | 'end') {
    if (event && (this.canMove || this.mode === CanvasMode.Drawing)) {
      let processed = false;
      const currentPoint = this.getClientPoint(event);
      if (type === 'start') {
        this.lastPoint = currentPoint;
        this.isMouseDown = true;
        this.isTouchEvent = typeof(event.touches) !== 'undefined';
        processed = true;
        if (this.mode === CanvasMode.Drawing) {
            const stroke = new Stroke();
            stroke.strokeColor = '#FFF';
            stroke.strokeWidth = 2;
            this.currentStroke = stroke;
        }
      } else if (type === 'move') {
        // 防止没有收到touchend事件时切换到鼠标操作引起的bug
        if (this.isTouchEvent && typeof(event.touches) === 'undefined') {
          this.onInputDeviceEvent(event, 'end');
          return;
        }
        if (this.isMouseDown) {
          const deltX = currentPoint.x - this.lastPoint.x;
          const deltY = currentPoint.y - this.lastPoint.y;
          if (this.mode === CanvasMode.Move) {
            const currentPos = this.currentImagePos;
            currentPos.left += deltX;
            currentPos.top += deltY;
            this.currentImagePos = currentPos;
            // 标识存在图片移动操作
            this.existImageMove = true;
          } else if ( this.mode === CanvasMode.Drawing) {
            const point1 = this.pageToCanvas(this.lastPoint.x, this.lastPoint.y);
            const point2 = this.pageToCanvas(currentPoint.x, currentPoint.y);
            this.drawLine(this.drawContext, point1, point2, this.currentStroke.strokeColor, this.currentStroke.strokeWidth);
          }
          this.lastPoint = currentPoint;
          processed = true;
        }
      } else if (type === 'end') {
        if (this.isMouseDown) {
          this.lastPoint = null;
          this.isMouseDown = false;
          this.isTouchEvent = false;
          processed = true;
        }
      }
      if (processed) {
        if (!event.defaultPrevented) {
          event.preventDefault();
      }
      }
    }
  }

  //#endregion

  //#region rotate 处理
  /**
   * 左旋图片
   */
  leftRotate() {
    let destDegree = this.currentDegree;
    destDegree -= 90;
    this.currentDegree = destDegree;
  }
  /**
   * 右旋图片
   */
  rightRotate() {
    let destDegree = this.currentDegree;
    destDegree += 90;
    this.currentDegree = destDegree;
  }
  //#endregion

  //#region scale处理
  /**
   * 放大图片
   */
  scaleOut() {
    let zoomLevel = this.currentScale;
    zoomLevel += this.scaleSeed;
    this.currentScale = zoomLevel;
  }
  /**
   * 缩小图片
   */
  scaleIn() {
    let zoomLevel = this.currentScale;
    zoomLevel -= this.scaleSeed;
    if (zoomLevel <= this.minScale) {
      zoomLevel = this.minScale;
    }
    this.currentScale = zoomLevel;
  }
  //#endregion

  //#region brightness处理
  /**
   * 增加图片亮度
   */
  brightnessUp() {
    let brightness = this.currentBrightness;
    brightness += this.brightnessSeed;
    this.currentBrightness = brightness;
  }
  /**
   * 降低图片亮度
   */
  brightnessDown() {
    let brightness = this.currentBrightness;
    brightness -= this.brightnessSeed;
    if (brightness <= this.minBrightness) {
      brightness = this.minBrightness;
    }
    this.currentBrightness = brightness;
  }
  //#endregion

  //#region 私有方法
  /**
   * 旋转角度变化处理
   * @param oldValue 旧的旋转角度值
   * @param newValue 新的旋转角度值
   */
  private onRotateDegreeChanged(oldValue: number, newValue: number) {
    this.refreshImageRotateStyle();
  }
  /**
   * 缩放比率变化处理
   * @param oldValue 旧的缩放值
   * @param newValue 新的缩放值
   */
  private onScaleChanged(oldValue: number, newValue: number) {
    this.refreshImageStyle();
  }
  /**
   * 亮度变化处理
   * @param oldValue 旧的亮度值
   * @param newValue 新的亮度值
   */
  private onBrightnessChanged(oldValue: number, newValue: number) {
    this.refreshImageStyle();
  }
  /**
   * 图片位置变化处理
   * @param oldValue 旧的位置值
   * @param newValue 旧的位置值
   */
  private onPositionChanged(oldValue: {'left': number, 'top': number}, newValue: {'left': number, 'top': number}) {
    if (!this.isLoading) {
    }
  }
  /**
   * 刷新图片缩放、亮度样式属性
   */
  private refreshImageStyle() {
    const scaleStr = `scale(${this.currentScale})`;
    const brightStr = `brightness(${this.currentBrightness})`;
    this.imageStyle = {
      'transform': scaleStr,
      '-moz-transform': scaleStr,
      '-ms-transform': scaleStr,
      '-o-transform': scaleStr,
      '-webkit-': scaleStr,
      '-webkit-filter': brightStr,
      'filter': brightStr,
    };
  }
  /**
   * 刷新图片旋转角度样式
   */
  private refreshImageRotateStyle() {
    const degree = this.currentDegree % 360;
    const degreeStr = `rotate(${degree}deg)`;
    this.rotateStyle = {
      'transform': degreeStr,
      '-moz-transform': degreeStr,
      '-ms-transform': degreeStr,
      '-o-transform': degreeStr,
      '-webkit-transform': degreeStr,
    };
  }
  /**
   * 获取图片属性值
   * @param attrName 属性名称
   */
  private getImageAtribute(attrName: string): string {
    return this.imgElement.getAttribute(attrName);
  }
  /**
   * 设置图片属性名称
   * @param attrName 属性名称
   * @param value 属性值
   */
  private setImageAtribute<T>(attrName: string, value: T) {
    this.imgElement.setAttribute(attrName, `${value}`);
  }
  /**
   * 获取触控或鼠标事件相对于页面的坐标点
   * @param event 触控或鼠标事件
   */
  private getClientPoint(event) {
    let point = {'x': 0, 'y': 0};
    if (event.touches) {
      const evt = <TouchEvent>event;
      const touch = evt.touches[0];
      point = {'x': touch.clientX, 'y': touch.clientY};
    } else if (event.pageX) {
      const evt = <MouseEvent>event;
      point = {'x': evt.clientX, 'y': evt.clientY};
    } else {
      point = null;
    }
    return point;
  }
  /**
   * 绑定图片移动事件
   */
  private attachMoveEvent() {
    this.deattachMoveEvent(); // 确保只绑定一次事件
    const element = this.canvasElement;
    if (element) {
      element.addEventListener('mousedown', this.moveStartAction);
      element.addEventListener('mousemove', this.movingAction);
      element.addEventListener('mouseup', this.moveEndAction);
      element.addEventListener('mouseout', this.moveEndAction);
      element.addEventListener('touchstart', this.moveStartAction);
      element.addEventListener('touchmove', this.movingAction);
      element.addEventListener('touchend', this.moveEndAction);
      element.addEventListener('touchcancel', this.moveEndAction);
    }
  }
  /**
   * 解除图片移动事件绑定
   */
  private deattachMoveEvent() {
    const element = this.canvasElement;
    if (element) {
      element.removeEventListener('mousedown', this.moveStartAction);
      element.removeEventListener('mousemove', this.movingAction);
      element.removeEventListener('mouseup', this.moveEndAction);
      element.removeEventListener('mouseout', this.moveEndAction);
      element.removeEventListener('touchstart', this.moveStartAction);
      element.removeEventListener('touchmove', this.movingAction);
      element.removeEventListener('touchend', this.moveEndAction);
      element.removeEventListener('touchcancel', this.moveEndAction);
    }
  }
  /**
   * 转换为canvas坐标
   * @param x x坐标
   * @param y y坐标
   */
  private pageToCanvas(x, y) {
    const bbox = this.canvasElement.getBoundingClientRect();
    return {x: Math.round(x - bbox.left), y: Math.round(y - bbox.top)};
  }
  /**
   * 绘制线条
   * @param point1 线段坐标点1
   * @param point2 线段坐标点2
   * @param lineColor 线段颜色
   * @param lineWidth 线段粗细
   */
  private drawLine(ctx: CanvasRenderingContext2D, point1: {'x': number, 'y': number}
  , point2: {'x': number, 'y': number}, lineColor: string, lineWidth: number) {
    if (ctx) {
      ctx.strokeStyle = lineColor;
      ctx.lineWidth = lineWidth;
      ctx.lineJoin = 'round';
      ctx.lineCap = 'round';
      ctx.save();
      ctx.beginPath();
      ctx.moveTo(point1.x, point1.y);
      ctx.lineTo(point2.x, point2.y);
      ctx.stroke();
      ctx.restore();
    }
  }
  /**
   * 获取图片html元素
   */
  private get imgElement(): HTMLImageElement {
    return this.img && <HTMLImageElement>this.img.nativeElement;
  }
  /**
   * 获取canvas画板html元素
   */
  private get canvasElement(): HTMLCanvasElement {
    return this.canvas && <HTMLCanvasElement>this.canvas.nativeElement;
  }
  /**
   * 获取绘制操作上下文
   */
  private get drawContext() {
    return this.canvasElement.getContext('2d');
  }
  //#endregion
}
